package br.ufpe.cin.mac.middleware.connectors.concrete;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import br.ufpe.cin.mac.middleware.connectors.ConcreteConnector;
import br.ufpe.cin.mac.util.ConnectionPackage;
import br.ufpe.cin.mac.util.Constants;
import br.ufpe.cin.mac.util.Message;

/**
 * Class HttpClient
 * 
 * @author Osmany
 * @author Rafael Roque
 * 
 */
public class HttpClient extends ConcreteConnector implements HttpClientMBean {

	private long seq;

	private Map<String, ConnectionPackage> connections;

	public HttpClient() {
		super(HttpClient.class.getCanonicalName());
		this.connections = Collections
				.synchronizedMap(new HashMap<String, ConnectionPackage>());
	}

	public void disconnect(String server) throws IOException {
		ConnectionPackage connection = this.connections.remove(server);
		Socket socket = connection.getSocket();
		socket.shutdownInput();
		socket.shutdownOutput();
		socket.close();
	}

	public Socket connect(String host) throws Exception {
		Socket socket = new Socket("localhost", Constants.HTTP_PORT);
		return socket;
	}

	public void invC(Message msg) {
		// TODO realizar processamento
		System.err.println("Http: Recebido pelo invC");
		this.buffer.put(msg.hashCode(), msg);

		sendNotification(msg.hashCode(), "invS");
	}

	public Message invS(int hashMsg) {
		try {
			final Message msg = (Message) this.buffer.remove(hashMsg);
			System.err.println("Http: Retirado do invS");
			System.err.println(connections.size() + "  "
					+ connections.containsKey(msg.getReceiver()) + " Seq "
					+ seq);
			this.send(msg);
			new Thread() {
				public void run() {
					receive(msg.getReceiver());
				}
			}.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public Message terC(int hashMsg) {
		System.err.println("Http: Retirado do terC");
		return (Message) this.buffer.remove(hashMsg);
	}

	public void terS(Message msg) {
		System.err.println("Http: Recebido pelo terS");
		this.buffer.put(msg.hashCode(), msg);

		sendNotification(msg.hashCode(), "terC");
	}

	private void send(Message msg) {
		try {
			String server = msg.getReceiver();
			ConnectionPackage pack;
			ObjectOutputStream out;
			if (!isConnected(server)) {
				Socket socket = this.connect(server);
				pack = new ConnectionPackage(socket);
				out = new ObjectOutputStream(socket.getOutputStream());
				pack.setOut(out);
				this.connections.put(server, pack);
			} else {
				pack = this.connections.get(server);
				System.err.println("Usando Conex�o existente!");
				out = pack.getOut();
			}
			out.writeObject(msg);
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void receive(String server) {

		ConnectionPackage pack = this.connections.get(server);
		System.err.println("Esperando: " + server);
		synchronized (pack) {
			System.err.println("Liberado: " + server);
			ObjectInputStream in = pack.getIn();
			try {
				/*
				 * int available = in.available(); while(available <= 0) {
				 * System.err.println(available); // Thread.sleep(5); available =
				 * in.available(); }
				 */
				Message msg = (Message) in.readObject();
				this.terS(msg);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private boolean isConnected(String server) {
		if (this.connections.containsKey(server)) {

			ConnectionPackage pack = this.connections.get(server);
			Socket socket = pack.getSocket();
			return socket.isConnected();
		} else
			return false;
	}

	@Override
	protected void msgManager(Message msg) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setHost(String host) {
		// TODO Auto-generated method stub

	}
}